// Epoll 模型 , 只负责 IO 中的等 -- ET 模式
// 用户告诉内核需要等什么

#pragma once 

#include <sys/epoll.h>
#include <unistd.h>

#include "Log.hpp"

using namespace LogModule;

const int size = 125;

class Epoll
{
private:
    // 事件帮助函数 , 因为添加和删除大部分代码一样
    void ModEventHelper(int sockfd, int op, uint32_t events)
    {
        struct epoll_event ev;
        ev.data.fd = sockfd;
        ev.events = events;

        int n = epoll_ctl(_epfd, op, sockfd, &ev);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "epoll_ctl error";
            return;
        }
        LOG(LogLevel::INFO) << "epoll_ctl success: " << sockfd;
    }

public:
    Epoll()
    {
        // 1. 创建 epoll 模型
        _epfd = epoll_create(size);
    }

    // ********* 管理事件 , 用户告诉内核需要什么 , 不需要什么  *********
    void AddEvent(int sockfd, uint32_t events)
    {
        ModEventHelper(sockfd, EPOLL_CTL_ADD, events);
    }

    void DelEvent(int sockfd)
    {
       int n = epoll_ctl(sockfd, EPOLL_CTL_DEL, sockfd, nullptr);
    }

    void ModifyEvent(int sockfd, uint32_t events)
    {
        ModEventHelper(sockfd, EPOLL_CTL_MOD, events);
    }

    // ********* 管理事件 , 用户告诉内核需要什么 , 不需要什么  *********

    // 真正的获取就绪事件 , 然后通知上层 , 返回就绪的文件描述符
    int WaitEvents(struct epoll_event revs[], int maxnum, int timeout)
    {
        int n = epoll_wait(_epfd, revs, maxnum, timeout);
        if (n < 0)
        {
            LOG(LogLevel::WARNING) << "epoll_wait error";
        }
        if (n == 0)
        {
            LOG(LogLevel::WARNING) << "epoll_wait timeout";
        }
        else
        {
            // 外部去做
        }
        return n;
    }

    ~Epoll()
    {
        if (_epfd > 0)
            close(_epfd);
    }

private:
    int _epfd; // epoll 创建的fd
};